#include "StdAfx.h"
#include "DteFunctions.h"

BOOL RecursiveElementEnumeration( IN const EnvDTE::ProjectPtr & spProject, IRecursiveEnumEvent * pEvent)
{
	BOOL bRet = FALSE;
	EnvDTE::CodeModelPtr spCodeModel;
	EnvDTE::CodeElementsPtr spCodeElements;

	if (SUCCEEDED(spProject->get_CodeModel(&spCodeModel)) && (spCodeModel) &&
		SUCCEEDED(spCodeModel->get_CodeElements(&spCodeElements)) && (spCodeElements))
	{
		bRet = RecursiveElementEnumeration(spCodeElements, pEvent);
	}

	return bRet;
}

BOOL RecursiveElementEnumeration(const EnvDTE::CodeElementsPtr & spCodeElements, IRecursiveEnumEvent * pEvent)
{
	ATLASSERT(spCodeElements != NULL);

	long lCount = 0;
	EnvDTE::CodeElementPtr spCodeElement;
	EnvDTE::CodeElementsPtr spMembers;
	EnvDTE::CodeNamespacePtr spCodeNamespace;
	EnvDTE::CodeTypePtr spCodeType;

	if ((spCodeElements) &&
		SUCCEEDED(spCodeElements->get_Count(&lCount)))
	{
		for (CComVariant var(1L); var.lVal <= lCount; ++var.lVal)
		{
			if (SUCCEEDED(spCodeElements->Item(var, &spCodeElement)))
			{
				spMembers = NULL;
				if (FALSE == pEvent->Element(spCodeElement))
					return FALSE;

				if (spCodeNamespace = spCodeElement)
					spCodeNamespace->get_Members(&spMembers);
				else if (spCodeType = spCodeElement)
					spCodeType->get_Members(&spMembers);
				else continue;

				if ( (spMembers) &&
					(FALSE == RecursiveElementEnumeration(spMembers, pEvent)))
				{
					return FALSE;
				}

			}
		} //for (CComVariant var(0L);
	}

	return TRUE;
}

BOOL DefineActiveProject( IN const CComPtr<EnvDTE80::DTE2> & spDTE, OUT EnvDTE::ProjectPtr & spActiveProject)
{
	BOOL bRet = FALSE;
	EnvDTE::DocumentPtr spDocument;
	EnvDTE::ProjectItemPtr spProjItem;
	IDispatchPtr spDispatch;
	EnvDTE::ProjectPtr spProject;
	EnvDTE::CodeModelPtr spCodeModel;
	EnvDTE::CodeElementsPtr spCodeElements;
	CComBSTR bstr, bstrVsCMLanguageVC(EnvDTE::vsCMLanguageVC);

	if (SUCCEEDED(spDTE->get_ActiveDocument(&spDocument)) && 
		(spDocument) && //for no project pages (like start up) no active document
		SUCCEEDED(spDocument->get_ProjectItem(&spProjItem)) && (spProjItem) &&
		SUCCEEDED(spProjItem->get_ContainingProject(&spProject)) && (spProject) &&
		SUCCEEDED(spProject->get_CodeModel(&spCodeModel)) && (spCodeModel) &&
		SUCCEEDED(spCodeModel->get_Language(&bstr)) &&
		(bstr == bstrVsCMLanguageVC))
	{
		spActiveProject = spProject;
		bRet = TRUE;
	}
	
	return bRet;
}

BOOL IsElementTestGroup(const EnvDTE::CodeTypePtr & spCT)
{
	if (spCT)
	{
		struct {
			LPCWSTR lpName;
			DWORD dwFlag;
		} aTestGroupFunctions[] = {
			L"MakeInstance", 1,
			L"DestroyInstance", 2,
			L"GetTestsFunc", 4
		};

		CComBSTR bstr;
		EnvDTE::vsCMElement eKind;
		spCT->get_Name(&bstr);
		spCT->get_Kind(&eKind);


		VCCodeModelLibrary::VCCodeClassPtr spClass;
		VCCodeModelLibrary::VCCodeStructPtr spStruct;
		EnvDTE::CodeElementsPtr spFunctions;

		if (spClass = spCT)
		{
			spClass->get_Functions(&spFunctions);
		} else if (spStruct = spCT)
		{
			spStruct->get_Functions(&spFunctions);
		}

		long nCount = 0;
		if ((spFunctions) &&
			SUCCEEDED(spFunctions->get_Count(&nCount)))
		{
			EnvDTE::CodeElementPtr spCodeElement;
			EnvDTE::CodeFunctionPtr spCodeFunction;
			CComBSTR bstrName;

			DWORD dwFFuncFound = 0; //1 - MakeInstance, 2 - DestroyInstance, 4 - GetTestsFunc

			for (CComVariant vt(1); vt.lVal <= nCount; ++vt.lVal)
			{
				if (SUCCEEDED(spFunctions->Item(vt, &spCodeElement)) &&
					(spCodeFunction = spCodeElement) &&
					SUCCEEDED(spCodeFunction->get_Name(&bstrName)))
				{
					for (int i = 0; i < _countof(aTestGroupFunctions); ++i)
					{
						if (((dwFFuncFound & aTestGroupFunctions[i].dwFlag) == 0) &&
							(bstrName == aTestGroupFunctions[i].lpName))
						{
							dwFFuncFound |= aTestGroupFunctions[i].dwFlag;

							if (dwFFuncFound == 7)
								return TRUE;
							break;
						}
					}
				}
			}
		} //if ((spFunctions) &&
	} //if (spCT)
	
	return FALSE;
}
